#include "JSONData.h"
#include "JSONUtil.h"
#include <sstream>
#include <vector>
#include <iosfwd>

simframework::json::JSON_Object::JSON_Object(SimWString str)
{
	size_t s = str.find_first_of(L"{") + 1;
	size_t e = str.find_last_of(L"}");
	m_valueStr = str.substr(s, e-s);

	m_startIt = m_valueStr.begin();
	m_endIt = m_valueStr.end();
}

simframework::json::JSON_Abstract* simframework::json::JSON_Object::getValue(simframework::json::JSON_Type type, SimWString name, int* error)
{
	for (; m_startIt != m_endIt; ++m_startIt)
	{
		SimWString key = JSONUtil::getKey(m_startIt, m_endIt);
		if (key.compare(name) == 0)
		{
			JSONUtil::removeSpaces(m_startIt, m_endIt);
			if (*m_startIt != ':')
			{
				std::cout << "Error : getValue should be :\n"; // to be removed
				if (error) *error = JSON_FAIL;
				return JSONUtil::getDefault(type);
			}
			m_startIt++; // skip :
			JSONUtil::removeSpaces(m_startIt, m_endIt);
			JSON_Abstract * data = NULL;

			switch (type)
			{
			case JSON_OBJECT:
				data = JSONUtil::getObjectValue(m_startIt, m_endIt, error);
				break;
			case JSON_ARRAY:
				data = JSONUtil::getArrayValue(m_startIt, m_endIt, error);
				break;
			case JSON_STRING:
				data = JSONUtil::getStringValue(m_startIt, m_endIt, error);
				break;
			case JSON_FLOAT:
				data = JSONUtil::getBooleanValue(m_startIt, m_endIt, error);
				break;
			case JSON_INTEGER:
				data = JSONUtil::getIntValue(m_startIt, m_endIt, error);
				break;
			case JSON_BOOLEAN:
				data = JSONUtil::getBooleanValue(m_startIt, m_endIt, error);
				break;
			default:
				break;
			}
			JSONUtil::cleanUp(m_startIt, m_endIt);
			return data;
		}
		else
		{
			JSONUtil::skipValue(m_startIt, m_endIt);
		}
		JSONUtil::cleanUp(m_startIt, m_endIt);

		if (m_startIt == m_endIt) break;
	}

	return JSONUtil::getDefault(type);
}

simframework::json::JSON_Object * simframework::json::JSON_Object::getObjectValueByKey(SimWString name, int* error)
{
	return static_cast<JSON_Object*>(getValue(JSON_OBJECT, name, error));
}

simframework::json::JSON_Array * simframework::json::JSON_Object::getArrayValueByKey(SimWString name, int* error)
{
	return static_cast<JSON_Array*>(getValue(JSON_ARRAY, name, error));
}

SimWString simframework::json::JSON_Object::getStringValueByKey(SimWString name, int* error)
{
	int err = JSON_SUCCESS;
	JSON_String* data = static_cast<JSON_String*>(getValue(JSON_STRING, name, (error ? error : &err)));
	SimWString ws = data->strValue;
	if (error && *error != JSON_FAIL || err != JSON_FAIL)
		delete data;
	return ws;
}

double simframework::json::JSON_Object::getFloatValueByKey(SimWString name, int* error)
{
	int err = JSON_SUCCESS;
	JSON_Float* data = static_cast<JSON_Float*>(getValue(JSON_FLOAT, name, (error ? error : &err)));
	double d = data->fValue;
	if (error && *error != JSON_FAIL || err != JSON_FAIL)
		delete data;
	return d;
}

int simframework::json::JSON_Object::getIntValueByKey(SimWString name, int* error)
{
	int err = JSON_SUCCESS;
	JSON_Integer* data = static_cast<JSON_Integer*>(getValue(JSON_INTEGER, name, (error ? error : &err)));
	int d = data->iValue;
	if (error && *error != JSON_FAIL || err != JSON_FAIL)
		delete data;
	return d;
}

bool simframework::json::JSON_Object::getBooleanValueByKey(SimWString name, int* error)
{
	int err = JSON_SUCCESS;
	JSON_Boolean* data = static_cast<JSON_Boolean*>(getValue(JSON_BOOLEAN, name, (error ? error : &err)));
	bool b = data->bValue;
	if (error && *error != JSON_FAIL || err != JSON_FAIL)
		delete data;
	return b;
}

simframework::json::JSON_Array::JSON_Array(SimWString str)
{
	size_t s = str.find_first_of(L"[") + 1;
	size_t e = str.find_last_of(L"]");
	m_valueStr = str.substr(s, e-s);
	m_valueCount = 0;

	m_startIt = m_valueStr.begin();
	m_endIt = m_valueStr.end();
}

simframework::json::JSON_Abstract *	simframework::json::JSON_Array::getValue(JSON_Type type, unsigned int id)
{
	JSON_Abstract * data = NULL;

	switch (type)
	{
	case JSON_OBJECT:
		data = JSONUtil::getObjectElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	case JSON_ARRAY:
		data = JSONUtil::getArrayElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	case JSON_STRING:
		data = JSONUtil::getStringElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	case JSON_FLOAT:
		data = JSONUtil::getFloatElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	case JSON_INTEGER:
		data = JSONUtil::getIntElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	case JSON_BOOLEAN:
		data = JSONUtil::getBooleanElementById(id, m_valueCount, m_startIt, m_endIt);
		break;
	default:
		break;
	}
	return data;
}

simframework::json::JSON_Object * simframework::json::JSON_Array::getObjectValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount)
	{
		if (error) *error = JSON_FAIL;
		return JSONUtil::getDefault(JSON_OBJECT);
	}

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	if (*m_startIt != '{')
	{
		std::cout << "getObjectValue Error : no {\n";
		return NULL;
	}
	return static_cast<JSON_Object*>(getValue(JSON_OBJECT, id));
}

simframework::json::JSON_Array * simframework::json::JSON_Array::getArrayValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount)
	{
		if (error) *error = JSON_FAIL;
		return JSONUtil::getDefault(JSON_ARRAY);
	}

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	if (*m_startIt != '[')
	{
		std::cout << "getObjectValue Error : no [\n";
		return NULL;
	}
	return static_cast<JSON_Array*>(getValue(JSON_ARRAY, id));
}

SimWString	simframework::json::JSON_Array::getStringValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount)
	{
		if (error) *error = JSON_FAIL;
		return L"";
	}

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	if (*m_startIt != '"')
	{
		std::cout << "getObjectValue Error : no \"\n";
		return NULL;
	}
	JSON_String* data = static_cast<JSON_String*>(getValue(JSON_STRING, id));
	return data->strValue;
}

double simframework::json::JSON_Array::getFloatValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount) return -1;

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	JSON_Float* data = static_cast<JSON_Float*>(getValue(JSON_FLOAT, id));
	return data->fValue;
}

int	simframework::json::JSON_Array::getIntValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount) return -1;

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	JSON_Integer* data = static_cast<JSON_Integer*>(getValue(JSON_INTEGER, id));
	return data->iValue;
}

bool simframework::json::JSON_Array::getBooleanValueForId(unsigned int id, int* error)
{
	if (m_valueCount > 0 && id <= m_valueCount) return false;

	JSONUtil::cleanUp(m_startIt, m_endIt);
	JSONUtil::removeSpaces(m_startIt, m_endIt);
	JSON_Boolean* data = static_cast<JSON_Boolean*>(getValue(JSON_BOOLEAN, id));
	return data->bValue;
}
